/*
 * Copyright 2007-2009 Perttu "celeron55" Ahola <celeron55@gmail.com>
 *
 * This file is part of jukumagic.
 *
 * jukumagic is free software: you can redistribute it and/or modify
 * it under the terms of the GNU General Public License as published by
 * the Free Software Foundation, either version 3 of the License, or
 * (at your option) any later version.
 *
 * jukumagic is distributed in the hope that it will be useful,
 * but WITHOUT ANY WARRANTY; without even the implied warranty of
 * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
 * GNU General Public License for more details.
 *
 * You should have received a copy of the GNU General Public License
 * along with jukumagic.  If not, see <http://www.gnu.org/licenses/>.
*/

#include "common.h"
#include "component.h"
#include "jukuapp.h"
#include <iostream>

Component::Component() : m_pos(0,0)
{
	//std::cout<<"Component"<<std::endl;
	m_footprint = NULL;
}

Component::~Component()
{
	//std::cout<<"~Component"<<std::endl;
	if(m_footprint) delete m_footprint;
	m_footprint = NULL;
}

void Component::WriteXML(TiXmlNode* root)
{
    TiXmlElement *element = new TiXmlElement("Component");
    root->LinkEndChild(element);
    element->SetAttribute("refdes", m_refdes.mb_str(wxConvUTF8));
    element->SetAttribute("value", m_value.mb_str(wxConvUTF8));
    element->SetAttribute("x", m_pos.m_x);
    element->SetAttribute("y", m_pos.m_y);
    m_footprint->WriteXML(element);
	WriteBaseXML(element);
}

JukuObject* Component::ReadFromXMLElement(TiXmlElement* element)
{
	//std::cout<<"Component::ReadFromXMLElement()"<<std::endl;

    Component *component = new Component();

	component->SetRefdes(wxString(element->Attribute("refdes"), wxConvUTF8));
	component->SetValue(wxString(element->Attribute("value"), wxConvUTF8));
	
	element->Attribute("x", &component->m_pos.m_x);
	element->Attribute("y", &component->m_pos.m_y);

	component->SetFootprint((Footprint*)Footprint::ReadFromXMLElement(element->FirstChildElement("Footprint")));
	
	component->m_footprint->SimplifyCoordinates(&component->m_pos);
	
	component->ReadBaseXML(element);

    return component;
}

void Component::Draw(wxDC &dc, wxWindow *window, wxPoint origin)
{
	//std::cout<<"Component(\""<<m_refdes.mb_str(wxConvUTF8)<<"\"::Draw()"<<std::endl;
	if(m_footprint){
		origin.x += m_pos.m_x;
		origin.y += m_pos.m_y;
		m_footprint->Draw(dc, window, origin);

		wxString *t = NULL;
		switch(wxGetApp().m_settings.m_component_show_infotype){
		case COMPONENT_INFO_NONE:
			break;
		case COMPONENT_INFO_REFDES:
			t = &m_refdes;	
			break;
		case COMPONENT_INFO_VALUE:
			t = &m_value;
			break;
		}
		
		if(t != NULL){
			dc.SetTextForeground(wxGetApp().m_settings.m_colour_component_textfg);
			dc.SetFont(wxGetApp().m_settings.m_font_component_text);
			int w, h;
			dc.GetTextExtent(*t, &w, &h);
			dc.SetPen(wxPen(wxGetApp().m_settings.m_colour_component_textbg, 0));
			dc.SetBrush(wxBrush(wxGetApp().m_settings.m_colour_component_textbg));
			dc.DrawRectangle(origin.x-50, origin.y+25, w, h);
			dc.DrawText(*t, origin.x-50, origin.y+25);
			/*dc.DrawRectangle(-w/2+xadd, -h/2+yadd, w, h);
			dc.DrawText(*t, -w/2 + xadd, -h/2 + yadd);*/
		}
	}
	else{
		wxPen pen(wxColour(255,0,0));
		wxBrush brush(wxColour(255,0,0));
		dc.SetPen(pen);
		dc.SetBrush(brush);
		dc.DrawRectangle(-50 + m_pos.m_x + origin.x, -50 + m_pos.m_y + origin.y, 100, 100);
	}
}

BoardRect Component::GetDrawArea()
{
	if(m_footprint){
		BoardRect br = m_footprint->GetDrawArea();
		br.m_x += m_pos.m_x;
		br.m_y += m_pos.m_y;
		return br;
	}
	else{
		return BoardRect(-50 + m_pos.m_x, -50 + m_pos.m_y, 100, 100);
	}
}

void Component::Move(int dx, int dy)
{
	m_pos.m_x += dx;
	m_pos.m_y += dy;
	ReportChange(OBJECT_CHANGE_CONTENTS);
}

bool Component::IsSelectedInPoint(int x, int y)
{
	return m_footprint->IsSelectedInPoint(x - m_pos.m_x, y - m_pos.m_y);
}

bool Component::IsSelectedInArea(int x1, int y1, int x2, int y2, bool touch_is_enough)
{
	return m_footprint->IsSelectedInArea(x1 - m_pos.m_x, y1 - m_pos.m_y,
			x2 - m_pos.m_x, y2 - m_pos.m_y, touch_is_enough);
}

void Component::SetSelected(bool selected)
{
	m_footprint->SetSelected(selected);
	JukuObject::SetSelected(selected);
}

void Component::Rotate(TurnDirection dir, BoardPoint origin)
{
	origin.m_x -= m_pos.m_x;
	origin.m_y -= m_pos.m_y;
	m_footprint->Rotate(dir, origin);
	m_footprint->SimplifyCoordinates(&m_pos);
	ReportChange(OBJECT_CHANGE_CONTENTS);
}

/*void Component::Rotate180()
{
	m_footprint->Rotate180();
}*/


BoardRect Component::GetPinExtents()
{
	BoardRect r = m_footprint->GetPinExtents();
	r.m_x += m_pos.m_x;
	r.m_y += m_pos.m_y;
	return r;
}

void Component::SetFootprint(Footprint *new_footprint)
{
	if(m_footprint) delete m_footprint;
	m_footprint = new_footprint;
	m_footprint->m_owner = this;
	m_footprint->SetSelected(GetSelected());
	ReportChange(OBJECT_CHANGE_CONTENTS);
}

Footprint* Component::GetFootprint()
{
	return m_footprint;
}

void Component::SimplifyCoordinates()
{
	m_footprint->SimplifyCoordinates(&m_pos);
}

//functions

Component* MakeTwoWireComponent(FootprintType type,
		BoardPoint p1, BoardPoint p2, const wxString &refdes, const wxString &value)
{
	std::cout<<"MakeComponent(): "
			<<"type="<<type<<", p1=("<<p1.m_x<<","<<p1.m_y<<")"
			<<" p2=("<<p2.m_x<<","<<p2.m_y<<") "
			<<"refdes = \""<<refdes.fn_str()<<"\""<<std::endl;

	Footprint *f = NULL;
	if(p1.m_x == p2.m_x){
		int fy = (p1.m_y < p2.m_y) ? p1.m_y : p2.m_y;
		int length = p2.m_y - p1.m_y;
		int abslength = abs(length);
		f = MakeTwoWireFootprint(type, abslength, 100);
		if(!f) return NULL;
		if(length<0){
			/*f->Rotate(CCW, BoardPoint(0, length/2));
			f->Rotate(CCW, BoardPoint(0, length/2));
			f->Move(p1.m_x, fy-length*2);*/
			f->Rotate(CCW, BoardPoint(0, abslength/2));
			f->Rotate(CCW, BoardPoint(0, abslength/2));
			f->Move(p1.m_x, fy);
		}
		else{
			f->Move(p1.m_x, fy);
		}
	}
	else if(p1.m_y == p2.m_y){
		int fx = (p1.m_x < p2.m_x) ? p1.m_x : p2.m_x;
		int length = p2.m_x - p1.m_x;
		int abslength = abs(length);
		f = MakeTwoWireFootprint(type, abslength, 100);
		if(!f) return NULL;
		if(length<0){
			/*f->Rotate(CW, BoardPoint(0,0));
			f->Move(fx-length, p1.m_y);*/
			f->Rotate(CW, BoardPoint(abslength/2,abslength/2));
			f->Move(fx, p1.m_y);
		}
		else{
			f->Rotate(CCW, BoardPoint(0, 0));
			f->Move(fx, p1.m_y);
		}
	}

	if(!f) return NULL;

	Component *c = new Component();

	if(c){
		c->SetFootprint(f);
		c->SimplifyCoordinates();
		c->SetRefdes(refdes);
		c->SetValue(value);
		return c;
	}

	delete f;
	
	return NULL;
}


